package com.harmony.pilot.agent.tools;

import com.harmony.pilot.agent.model.*;
import com.harmony.pilot.agent.service.LLMServiceClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@Component
@Slf4j
public class GitOperationTool implements AgentTool {
    
    private final LLMServiceClient llmServiceClient;
    
    public GitOperationTool(LLMServiceClient llmServiceClient) {
        this.llmServiceClient = llmServiceClient;
    }
    
    @Override
    public String getName() {
        return "git_operation";
    }
    
    @Override
    public String getDescription() {
        return "执行Git操作，包括提交、推送、查看状态等";
    }
    
    @Override
    public String getParametersSchema() {
        return """
            {
              "type": "object",
              "properties": {
                "operation": {
                  "type": "string",
                  "enum": ["status", "commit", "push", "diff", "log"],
                  "description": "Git操作类型"
                },
                "message": {
                  "type": "string",
                  "description": "提交信息（用于commit操作）"
                },
                "files": {
                  "type": "array",
                  "items": {"type": "string"},
                  "description": "要提交的文件列表（可选，默认提交所有变更）"
                }
              },
              "required": ["operation"]
            }
            """;
    }
    
    @Override
    public boolean canHandle(Intent intent, ConversationContext context) {
        return intent.getType() == Intent.IntentType.GIT_OPERATION;
    }
    
    @Override
    public double getRelevanceScore(Intent intent, ConversationContext context) {
        if (intent.getType() == Intent.IntentType.GIT_OPERATION) {
            return 0.95;
        }
        return 0.0;
    }
    
    @Override
    public ToolResult execute(ToolRequest request) {
        Map<String, Object> params = request.getParameters();
        if (params == null) {
            params = new HashMap<>();
        }
        
        String operation = (String) params.get("operation");
        String projectRoot = request.getContext().getProjectRoot();
        
        if (projectRoot == null || projectRoot.isEmpty()) {
            return ToolResult.error("项目根目录未指定");
        }
        
        try {
            switch (operation) {
                case "status":
                    return executeStatus(projectRoot);
                case "commit":
                    String message = (String) params.get("message");
                    @SuppressWarnings("unchecked")
                    List<String> files = (List<String>) params.get("files");
                    return executeCommit(projectRoot, message, files, request.getUserMessage());
                case "push":
                    return executePush(projectRoot);
                case "diff":
                    return executeDiff(projectRoot);
                case "log":
                    return executeLog(projectRoot);
                default:
                    return ToolResult.error("不支持的Git操作: " + operation);
            }
        } catch (Exception e) {
            log.error("Git operation failed", e);
            return ToolResult.error("Git操作失败: " + e.getMessage());
        }
    }
    
    private ToolResult executeStatus(String projectRoot) {
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "status", "--porcelain");
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                return ToolResult.error("Git status命令执行失败");
            }
            
            Map<String, Object> data = new HashMap<>();
            data.put("status", output.toString());
            data.put("hasChanges", !output.toString().trim().isEmpty());
            
            return ToolResult.success("Git状态获取成功", data);
        } catch (Exception e) {
            log.error("Failed to execute git status", e);
            return ToolResult.error("获取Git状态失败: " + e.getMessage());
        }
    }
    
    private ToolResult executeCommit(String projectRoot, String message, 
                                    List<String> files, String userMessage) {
        try {
            // 1. 获取变更状态
            ToolResult statusResult = executeStatus(projectRoot);
            if (!statusResult.isSuccess()) {
                return statusResult;
            }
            
            @SuppressWarnings("unchecked")
            Map<String, Object> statusData = (Map<String, Object>) statusResult.getData();
            Boolean hasChanges = (Boolean) statusData.get("hasChanges");
            
            if (!hasChanges) {
                return ToolResult.success("没有需要提交的变更");
            }
            
            // 2. 分析代码变更
            List<FileChange> changes = analyzeChanges(projectRoot);
            
            // 3. 生成提交信息（如果没有提供）
            if (message == null || message.isEmpty()) {
                message = generateCommitMessage(changes, userMessage);
            }
            
            // 4. 添加文件
            ProcessBuilder pb = new ProcessBuilder("git", "add", ".");
            if (files != null && !files.isEmpty()) {
                List<String> command = new ArrayList<>();
                command.add("git");
                command.add("add");
                command.addAll(files);
                pb = new ProcessBuilder(command);
            }
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            int exitCode = process.waitFor();
            
            if (exitCode != 0) {
                return ToolResult.error("Git add命令执行失败");
            }
            
            // 5. 提交
            pb = new ProcessBuilder("git", "commit", "-m", message);
            pb.directory(new File(projectRoot));
            process = pb.start();
            exitCode = process.waitFor();
            
            if (exitCode != 0) {
                // 读取错误信息
                StringBuilder error = new StringBuilder();
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        error.append(line).append("\n");
                    }
                }
                return ToolResult.error("Git commit失败: " + error.toString());
            }
            
            // 6. 获取提交信息
            pb = new ProcessBuilder("git", "log", "-1", "--pretty=format:%H%n%an%n%ae%n%ad%n%s");
            pb.directory(new File(projectRoot));
            process = pb.start();
            
            StringBuilder commitInfo = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    commitInfo.append(line).append("\n");
                }
            }
            
            Map<String, Object> data = new HashMap<>();
            data.put("commitMessage", message);
            data.put("commitInfo", commitInfo.toString());
            data.put("changes", changes);
            
            return ToolResult.success("代码提交成功", data);
        } catch (Exception e) {
            log.error("Failed to execute git commit", e);
            return ToolResult.error("Git提交失败: " + e.getMessage());
        }
    }
    
    private ToolResult executePush(String projectRoot) {
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "push");
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                StringBuilder error = new StringBuilder();
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        error.append(line).append("\n");
                    }
                }
                return ToolResult.error("Git push失败: " + error.toString());
            }
            
            return ToolResult.success("代码推送成功: " + output.toString());
        } catch (Exception e) {
            log.error("Failed to execute git push", e);
            return ToolResult.error("Git推送失败: " + e.getMessage());
        }
    }
    
    private ToolResult executeDiff(String projectRoot) {
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "diff");
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            Map<String, Object> data = new HashMap<>();
            data.put("diff", output.toString());
            
            return ToolResult.success("Git diff获取成功", data);
        } catch (Exception e) {
            log.error("Failed to execute git diff", e);
            return ToolResult.error("获取Git diff失败: " + e.getMessage());
        }
    }
    
    private ToolResult executeLog(String projectRoot) {
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "log", "--oneline", "-10");
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            Map<String, Object> data = new HashMap<>();
            data.put("log", output.toString());
            
            return ToolResult.success("Git log获取成功", data);
        } catch (Exception e) {
            log.error("Failed to execute git log", e);
            return ToolResult.error("获取Git log失败: " + e.getMessage());
        }
    }
    
    private List<FileChange> analyzeChanges(String projectRoot) {
        List<FileChange> changes = new ArrayList<>();
        
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "status", "--porcelain");
            pb.directory(new File(projectRoot));
            Process process = pb.start();
            
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.trim().isEmpty()) continue;
                    
                    String status = line.substring(0, 2).trim();
                    String filePath = line.substring(3);
                    
                    FileChange change = new FileChange();
                    change.setFilePath(filePath);
                    
                    if (status.startsWith("A")) {
                        change.setType("ADDED");
                    } else if (status.startsWith("D")) {
                        change.setType("DELETED");
                    } else if (status.startsWith("M")) {
                        change.setType("MODIFIED");
                    } else if (status.startsWith("R")) {
                        change.setType("RENAMED");
                    }
                    
                    changes.add(change);
                }
            }
        } catch (Exception e) {
            log.error("Failed to analyze changes", e);
        }
        
        return changes;
    }
    
    private String generateCommitMessage(List<FileChange> changes, String userMessage) {
        try {
            StringBuilder prompt = new StringBuilder();
            prompt.append("请为以下代码变更生成一个清晰的Git提交信息。");
            prompt.append("遵循Conventional Commits规范（如：feat:, fix:, docs:等）。\n\n");
            
            if (userMessage != null && !userMessage.isEmpty()) {
                prompt.append("用户描述：").append(userMessage).append("\n\n");
            }
            
            prompt.append("变更文件：\n");
            for (FileChange change : changes) {
                prompt.append("- ").append(change.getFilePath())
                      .append(" (").append(change.getType()).append(")\n");
            }
            
            prompt.append("\n请生成提交信息（只返回提交信息本身，不要包含其他内容）：");
            
            String message = llmServiceClient.generate(prompt.toString());
            if (message != null && !message.trim().isEmpty()) {
                return message.trim();
            }
        } catch (Exception e) {
            log.error("Failed to generate commit message with LLM", e);
        }
        
        return generateSimpleCommitMessage(changes, userMessage);
    }
    
    private String generateSimpleCommitMessage(List<FileChange> changes, String userMessage) {
        StringBuilder message = new StringBuilder();
        
        // 分析变更类型
        long added = changes.stream().filter(c -> "ADDED".equals(c.getType())).count();
        long modified = changes.stream().filter(c -> "MODIFIED".equals(c.getType())).count();
        long deleted = changes.stream().filter(c -> "DELETED".equals(c.getType())).count();
        
        if (added > 0 && modified == 0 && deleted == 0) {
            message.append("feat: ");
        } else if (deleted > 0 && added == 0 && modified == 0) {
            message.append("refactor: ");
        } else {
            message.append("chore: ");
        }
        
        if (userMessage != null && !userMessage.isEmpty()) {
            message.append(userMessage);
        } else {
            message.append("更新代码");
            if (added > 0) message.append("，新增").append(added).append("个文件");
            if (modified > 0) message.append("，修改").append(modified).append("个文件");
            if (deleted > 0) message.append("，删除").append(deleted).append("个文件");
        }
        
        return message.toString();
    }
    
    @Data
    private static class FileChange {
        private String filePath;
        private String type;
    }
}

